package com.gugee.tiktok.data.consumer.challenge.core.service;

import cn.hutool.core.date.DateUtil;
import com.gugee.common.thread.ScheduleTemplate;
import com.gugee.tiktok.common.model.dal.blogger.BloggerTypeRepository;
import com.gugee.tiktok.common.model.dal.challenge.ChallengeRecordRepository;
import com.gugee.tiktok.common.model.dal.challenge.ChallengeRepository;
import com.gugee.tiktok.common.model.dal.music.MusicTypeRelativeRepository;
import com.gugee.tiktok.common.model.es.challenge.ESCategory;
import com.gugee.tiktok.common.model.es.challenge.ESChallenge;
import com.gugee.tiktok.common.model.es.challenge.ESWeekGrowth;
import com.gugee.tiktok.common.model.es.music.ESVideo;
import com.gugee.tiktok.common.model.mysql.*;
import com.gugee.tiktok.common.model.ranking.GrowthData;
import com.gugee.tiktok.common.model.spider.aweme.BloggerAwemesResponse;
import com.gugee.tiktok.common.model.spider.challenge.ChallengeResponse;
import com.gugee.tiktok.data.common.msg.HashtagMessage;
import com.gugee.tiktok.data.consumer.challenge.config.ChallengeAppConfig;
import com.gugee.tiktok.data.consumer.challenge.core.service.mapper.ChallengeMapper;
import com.gugee.tiktok.data.consumer.challenge.core.service.mapper.ChallengeRecordMapper;
import com.gugee.tiktok.data.consumer.challenge.core.spider.ChallengeSpiderClient;
import com.gugee.tiktok.data.consumer.challenge.core.spider.TikCodeSpiderClient;
import com.gugee.tiktok.data.consumer.challenge.monitor.AopUtil;
import com.gugee.tiktok.data.consumer.challenge.monitor.Monitor;

import com.xiguaji.boot.filecenter.FileTemplate;
import com.xiguaji.boot.toolkit.DateTimeUtils;
import com.xiguaji.boot.toolkit.JsonUtil;
import com.xiguaji.boot.toolkit.ThreadPoolUtils;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;


@Service
@Slf4j
public class ChallengeService {

    private static String CHALLENGE_INDEX = "challenge_index";
    private static String AWEME_INDEX = "aweme_index_";
    @Autowired
    ChallengeSpiderClient challengeSpiderClient;

    @Autowired
    TikCodeSpiderClient tikCodeSpiderClient;

    @Autowired
    ChallengeRecordRepository challengeRecordRepository;

    @Autowired
    ChallengeRepository challengeRepository;

    @Autowired
    MusicTypeRelativeRepository musicTypeRelativeRepository;

    @Autowired
    BloggerTypeRepository bloggerTypeRepository;

    @Autowired
    ChallengeMapper challengeMapper;

    @Autowired
    ChallengeRecordMapper challengeRecordMapper;

    @Autowired
    RestHighLevelClient client;

    @Autowired
    ChallengeAppConfig challengeAppConfig;

    @Autowired
    ESChallenge.ESChallengeMapping esChallengeMapping;


    @Value("${xiguaji.oss.bucket.tiktok.videoImg}")
    String picBucket;

    @Autowired
    FileTemplate fileTemplate;


    Map<String, BloggerType> typeMap;

    Map<Long, BloggerType> typeMapById;


    @Autowired
    ScheduleTemplate scheduleTemplate;
    ForkJoinPool forkJoinPool;

    // ForkJoinPool forkJoinPool;

    @PostConstruct
    private void postConstruct(){
        List<BloggerType> types = bloggerTypeRepository.findAll();
        typeMap = new HashMap<>();
        typeMapById = new HashMap<>();
        types.forEach( t-> typeMap.put(t.getName(),t));
        types.forEach( t-> typeMapById.put(t.getId(),t));
        forkJoinPool = ThreadPoolUtils.forkJoinPool(challengeAppConfig.getCorePollSize(), "RefreshChallenge work");
        scheduleTemplate.attach("RefreshChallenge work",forkJoinPool);
        // customPoolMain = scheduleTemplate.getCustomThreadPool(updateMusicMain, corePollSize, corePollSize, 0, queueSize, TimeUnit.MINUTES);
        // forkJoinPool = ThreadPoolUtils.forkJoinPool(corePollSize, "RefreshMusic work");
    }


    
    @Monitor(value = "批量更新话题数据",maxTime = 1,timeUnit = Monitor.TimeUnit.MINUTE)
    public void updateChallenge(List<HashtagMessage> hashtagMessages){
        log.info("话题过滤前的长度：{}",hashtagMessages.size());
        long start = System.currentTimeMillis()/1000;
        List<Challenge> challenges = new ArrayList<>();

        HashSet<Long> challengeIds = new HashSet<>();
        hashtagMessages.forEach(hashtagMessage -> {
            if(hashtagMessage.getHid() > 0){
                challengeIds.add(hashtagMessage.getHid());
            }
        });

        log.info("准备更新话题数据，共{}条",challengeIds.size());

        try {
            forkJoinPool.submit(() ->
                    challengeIds.parallelStream().forEach(h -> {
                        try {
                            challenges.add(AopUtil.getSelf(this).updateChallenge(h));
                        } catch (Exception ex) {
                            log.error("话题更新出错!cid:{}",h,ex);
                        }
                    })
            ).get();
        } catch (InterruptedException e) {
            log.error("话题多线程更新出错!",e);
        } catch (ExecutionException e) {
            log.error("话题多线程更新出错!",e);
        }


        // 批量保存mysql
        List<Challenge> completeChallenges = AopUtil.getSelf(this).saveChallenge(challenges);

        List<ESChallenge> esChallenges = esChallengeMapping.mappger(completeChallenges);

        // 批量保存ES
        AopUtil.getSelf(this).saveToES(esChallenges);
        log.info("话题数据更新完成，原数据为{}条，成功更新{}条,总用时{}秒",challengeIds.size(),challenges.size(),System.currentTimeMillis()/1000 -start);

    }

    /**
     * 更新话题
     * @param cid
     */

    @Monitor(value = "访问接口获取话题详情")
    public Challenge updateChallenge(long cid){
        ChallengeResponse challengeResponse = AopUtil.getSelf(this).spiderChallengeDetail(cid);
        Challenge challenge = challengeMapper.mapper(challengeResponse.getCh_info());
        Optional<Challenge> challengeOptional = challengeRepository.findByCid(cid);

        if(challengeOptional.isPresent()){
            challenge.setRegion(challengeOptional.get().getRegion());
            challenge.setId(challengeOptional.get().getId());
            challenge.setQrCode(challengeOptional.get().getQrCode());
            challenge.setCreateBy(challengeOptional.get().getCreateBy());
            challenge.setCreateTime(challengeOptional.get().getCreateTime());
        }else {
            challenge.setCreateBy("add challenge data");
            challenge.setCreateTime(System.currentTimeMillis()/1000);
        }
        challenge.setUpdateBy("update challenge");
        challenge.setUpdateTime(System.currentTimeMillis()/1000);


        // 归属国家
        if(StringUtils.isEmpty(challenge.getRegion())){
            challenge.setRegion(getRegion(challenge.getCid()));
        }

        // 二维码
        /*if(StringUtils.isEmpty(challenge.getQrCode())){
            challenge.setQrCode(AopUtil.getSelf(this).getQrCode(cid));
        }*/

        // 打点记录并获取增量值
        saveRecord(cid,challenge.getUserCount(),challenge.getViewCount());
        val avgGrowth = getAvgGrowth(challenge.getCid());
        challenge.setUserGrowth(avgGrowth.getUserGrowth());
        challenge.setViewGrowth(avgGrowth.getViewGrowth());

        // 七天增量值
        challenge.setWeekGrowth(JsonUtil.parseJson(getWeekGrowth(cid)));

        // top3视频
        challenge.setTopVideos(JsonUtil.parseJson(getTopAweme(cid)));

        return challenge;
    }

    public List<Challenge> saveChallenge(List<Challenge> challenges){
        List<Challenge> newChallenges = new ArrayList<>();
        List<Challenge> updateChallenges = new ArrayList<>();
        challenges.forEach(challenge -> {
            if(null == challenge.getId()){
                newChallenges.add(challenge);
            }else {
                updateChallenges.add(challenge);
            }
        });

        if(updateChallenges.size() > 0) {
            AopUtil.getSelf(this).batchUpdateChallenge(updateChallenges);
        }

        if(newChallenges.size() > 0){
            AopUtil.getSelf(this).batchSaveChallenge(newChallenges);
            return challengeRepository.findByCid(challenges);
        }

        return updateChallenges;
    }


    @Monitor(value = "批量更新话题详情到MYSQL",maxTime = 5)
    public void batchUpdateChallenge(List<Challenge> challenges){
        // 批量保存mysql
        long start = System.currentTimeMillis()/1000;
        challengeRepository.batchUpdate(challenges);
        if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) log.info("手动打印批量更新话题详情到MYSQL,数量：{},用时：{}秒",challenges.size(),System.currentTimeMillis()/1000 -start);
    }

    @Monitor(value = "批量插入话题详情到MYSQL",maxTime = 5)
    public void batchSaveChallenge(List<Challenge> challenges){
        // 批量保存mysql
        long start = System.currentTimeMillis()/1000;
        try{

            challengeRepository.insertUpdate(challenges);
        }catch (Exception e){
            log.error("话题批量保存异常，重试一次");
            List<Challenge> challengeList = challengeRepository.findByCid(challenges);
            challengeList.removeIf( c -> {
                for (Challenge challenge : challengeList) {
                    if(c.getCid() == challenge.getCid()){
                        return true;
                    }
                }
                return false;
            });


            challengeRepository.insertUpdate(challenges);
        }

        if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) log.info("手动打印批量插入话题详情到MYSQL,数量：{},用时：{}秒",challenges.size(),System.currentTimeMillis()/1000 -start);
    }


    @Monitor(value = "爬虫获取话题详情",maxTime = 5)
    public ChallengeResponse spiderChallengeDetail(long cid){
        long start = System.currentTimeMillis()/1000;
        val challengeResponse = challengeSpiderClient.get(cid);

        if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) {
            log.info("手动爬虫获取话题详情,用时：{}秒",System.currentTimeMillis()/1000 -start);
        }
        return challengeResponse;
    }

    @Monitor(value = "爬虫获取话题视频列表",maxTime = 5)
    public BloggerAwemesResponse spiderVideos(long cid){
        long start = System.currentTimeMillis()/1000;
        val awemes = challengeSpiderClient.getAwemes(cid, 3);

        if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) {
            log.info("手动爬虫获取话题视频列表,用时：{}秒",System.currentTimeMillis()/1000 -start);
        }
        return awemes;
    }




    /**
     * 打点记录话题增量数据并返回
     * @param cid
     * @param userCount
     * @return
     */

    public ChallengeRecord saveRecord(long cid,long userCount,long viewCount){
        int todayCode = Integer.parseInt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        int yesterdayCode = Integer.parseInt(LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMdd")));

        Optional<ChallengeRecord> todayRecordOptional = challengeRecordRepository.findByCidAndDateCode(cid,todayCode);
        Optional<ChallengeRecord> yesterdayRecordOptional = challengeRecordRepository.findByCidAndDateCode(cid,yesterdayCode);
        ChallengeRecord challengeRecord = new ChallengeRecord();

        if(todayRecordOptional.isPresent()){
            challengeRecord = todayRecordOptional.get();
            challengeRecord.setUpdateTime(System.currentTimeMillis()/1000);
            challengeRecord.setUpdateBy("update record music data");
        }else {
            challengeRecord.setCid(cid);
            challengeRecord.setDateCode(todayCode);
            challengeRecord.setDateCode(todayCode);
            challengeRecord.setViewGrowth(0l);
            challengeRecord.setUserGrowth(0l);
            challengeRecord.setCreateBy("add record music data");
            challengeRecord.setUpdateBy("add record music data");
            challengeRecord.setCreateTime(System.currentTimeMillis()/1000);
            challengeRecord.setUpdateTime(System.currentTimeMillis()/1000);
            challengeRecord.setUserGrowth(0l);
        }
        challengeRecord.setUserCount(userCount);
        challengeRecord.setViewCount(viewCount);

        if(yesterdayRecordOptional.isPresent()){
            challengeRecord.setUserGrowth(challengeRecord.getUserCount() - yesterdayRecordOptional.get().getUserCount());
            challengeRecord.setViewGrowth(challengeRecord.getViewCount() - yesterdayRecordOptional.get().getViewCount());
        }
        challengeRecordRepository.save(challengeRecord);
        return challengeRecord;
    }

    public GrowthData getAvgGrowth(long cid){
        int todayCode = Integer.parseInt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        int beforeCode = Integer.parseInt(LocalDateTime.now().minusDays(challengeAppConfig.getAvgDay()).format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        return challengeRecordRepository.findByGrowthData(cid,beforeCode,todayCode);
    }


    /**
     * 获取二维码
     * @param cid
     * @return
     */

    @Monitor(value = "获取二维码",maxTime = 5)
    public String getQrCode(long cid){
        try{
            long start = System.currentTimeMillis()/1000;
            val qrCodeResponse = tikCodeSpiderClient.get(cid, 2);
            if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) {
                log.info("手动获取二维码,用时：{}秒",System.currentTimeMillis()/1000 -start);
            }
            if(CollectionUtils.isEmpty(qrCodeResponse.getQrcode_url().getUrl_list())) {
                return "";
            }
            return qrCodeResponse.getQrcode_url().getUrl_list().get(0);
        }catch (Exception e){
            log.error("获取二维码失败，cid:{}",cid,e);
            return "";
        }
    }

    /**
     * 获取国家
     * @param cid
     * @return
     */

    public String getRegion(long cid){
        String region = "";
        SearchRequest searchRequest = new SearchRequest(getEsIndex());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(QueryBuilders.nestedQuery("challenges",QueryBuilders.matchQuery("challenges.hid",cid), ScoreMode.Total));
        searchSourceBuilder.query(boolQueryBuilder);
        //TermsAggregationBuilder builder = AggregationBuilders.terms("regions").field("region").executionHint("map");
        TermsAggregationBuilder builder = AggregationBuilders.terms("regions").field("region");
        searchSourceBuilder.aggregation(builder);
        searchRequest.source(searchSourceBuilder);
        try {

            long esSearchStart = System.currentTimeMillis()/1000;
            SearchResponse searchResponse =  client.search(searchRequest,RequestOptions.DEFAULT);

            if(System.currentTimeMillis()/1000 -esSearchStart > challengeAppConfig.getTimeLimit()) {
                log.info("话题国家ES查询,用时：{}秒",System.currentTimeMillis()/1000 -esSearchStart);
            }

            if(null != searchResponse.getAggregations()){
                val hashtagName = (Terms) searchResponse.getAggregations().get("regions");
                val buckets = hashtagName.getBuckets();

                if(buckets.size() > 0){
                    region = buckets.get(0).getKeyAsString();
                }
            }

            return region;
        } catch (IOException e) {
            log.error("es aggre error!",e);
        }
        return region;
    }

    private String getEsIndex(){
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime before = LocalDateTime.now().minusDays(challengeAppConfig.getLatestDays());
        StringBuffer stringBuffer = new StringBuffer();

        while(Integer.parseInt(before.format(DateTimeFormatter.ofPattern("yyyMM"))) <= Integer.parseInt(now.format(DateTimeFormatter.ofPattern("yyyMM")))){
            stringBuffer.append(AWEME_INDEX+ DateUtil.format(before,"yyyyMM")).append(",");
            before = before.plusDays(30);
        }
        return stringBuffer.toString().substring(0,stringBuffer.toString().length()-1);
    }

    /**
     * 获取七天视频增长趋势图
     * @param cid
     * @return
     */

    public List<ESWeekGrowth> getWeekGrowth(long cid){
        int startCode = Integer.parseInt(LocalDateTime.now().minusDays(7).format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        int afterCode = Integer.parseInt(LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        // int afterCode = Integer.parseInt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        List<ChallengeRecord> challengeRecords = challengeRecordRepository.findByCidAndDateCodeBetweenOrderByDateCode(cid,startCode,afterCode);
        return challengeRecordMapper.mapperToES(challengeRecords);
    }

    /**
     * 保存到ES
     * @param esChallenges
     */

    @Monitor(value = "批量将话题保存到ES",maxTime = 5)
    public void saveToES(List<ESChallenge> esChallenges){
        BulkRequest bulkRequest = new BulkRequest();

        try {
            forkJoinPool.submit(() ->
                    esChallenges.parallelStream().forEach(c -> {
                        try {
                            //分类
                            c.setCategories(AopUtil.getSelf(this).setBelongType(c.getCid()));
                            IndexRequest indexRequest = new IndexRequest(CHALLENGE_INDEX);
                            indexRequest.id(String.valueOf(c.getId()));
                            indexRequest.source(JsonUtil.parseJson(c), XContentType.JSON);
                            bulkRequest.add(indexRequest);
                        } catch (Exception ex) {
                            log.error("话题分类出错!mid:{}" , c.getCid(), ex);
                        }
                    })
            ).get();
        }catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        try{

            long start = System.currentTimeMillis()/1000;
            client.bulk(bulkRequest,RequestOptions.DEFAULT);
            if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) {
                log.info("手动批量将话题保存到ES,数量：{},用时：{}秒",esChallenges.size(),System.currentTimeMillis()/1000 -start);
            }
        }catch (Exception e){
            log.error("save to es error",e);
        }
    }

    /**
     * 获取话题所属分类
     * @param cid
     * @return
     */
    @Monitor(value = "话题分类",maxTime = 5)
    public List<ESCategory> setBelongType(long cid){
        long start = System.currentTimeMillis()/1000;
        List<ESCategory> esCategories = new ArrayList<>();
        if(true){
            return esCategories;
        }
        SearchRequest searchRequest = new SearchRequest(getEsIndex());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.should(QueryBuilders.nestedQuery("challenges",QueryBuilders.matchQuery("challenges.cid",cid), ScoreMode.Total));
        searchSourceBuilder.query(boolQueryBuilder);
        // TermsAggregationBuilder builder = AggregationBuilders.terms("awemeTypes").field("awemeType").executionHint("map");
        TermsAggregationBuilder builder = AggregationBuilders.terms("awemeTypes").field("awemeType");
        searchSourceBuilder.aggregation(builder);

        try {
            long esSearchStart = System.currentTimeMillis()/1000;
            SearchResponse searchResponse =  client.search(searchRequest,RequestOptions.DEFAULT);
            if(System.currentTimeMillis()/1000 -esSearchStart > challengeAppConfig.getTimeLimit()) {
                log.info("话题分类ES查询,用时：{}秒",System.currentTimeMillis()/1000 -esSearchStart);
            }
            val aggregations = searchResponse.getAggregations();

            if(null != aggregations){
                val hashtagName = (Terms) searchResponse.getAggregations().get("awemeTypes");
                val buckets = hashtagName.getBuckets();

                AtomicInteger sum = new AtomicInteger(0);
                buckets.forEach( bucket -> sum.addAndGet((int) bucket.getDocCount()));

                if(sum.get() > 0){
                    for (int i = 0; i < buckets.size(); i++) {

                        if (i > 0){
                            BigDecimal bigDecimal = new BigDecimal(buckets.get(i).getDocCount());
                            double percent =bigDecimal.divide(new BigDecimal(sum.get()),3, RoundingMode.FLOOR).multiply(new BigDecimal(100)).setScale(2).doubleValue();
                            if(percent <20){
                                break;
                            }
                        }
                        val type = typeMap.get(buckets.get(i).getKeyAsString());

                        if(null == type){
                            continue;
                        }
                        ESCategory esCategory = new ESCategory();
                        esCategory.setId(type.getId());
                        esCategory.setTypeName(type.getName());
                        esCategories.add(esCategory);
                    }
                }
            }

        } catch (IOException e) {
            log.error("es aggregations error!",e);
        }
        if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) {
            log.info("手动话题分类,用时：{}秒;",
                    System.currentTimeMillis()/1000 -start);
        }
        return esCategories;
    }


    public List<ESVideo> getTopAweme(long cid){
        BloggerAwemesResponse response = AopUtil.getSelf(this).spiderVideos(cid);
        List<ESVideo> esVideos = new ArrayList<>();

        try {
            forkJoinPool.submit(()->{
                for (int i = 0; i < response.getAweme_list().size(); i++) {
                    if(i >2){
                        break;
                    }
                    ESVideo esVideo = new ESVideo();
                    esVideo.setDiggCount(response.getAweme_list().get(i).getStatistics().getPlay_count());
                    esVideo.setCover(setAwemeCover(response.getAweme_list().get(i).getAweme_id(),response.getAweme_list().get(i).getVideo().getCover().getUrl_list().get(0)));
                    esVideo.setShareUrl(response.getAweme_list().get(i).getShare_url());
                    esVideos.add(esVideo);
                }
            }).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return esVideos;
    }

    private String setAwemeCover(String awemeId,String coverUrl){
        String newCoverUrl = coverUrl;
        long start = System.currentTimeMillis()/1000;
        try {
            newCoverUrl = fileTemplate.putNetImg(picBucket,"video_" + DateTimeUtils.millsecond2DateStr(start,"yyyyMMdd") + "/" + awemeId,coverUrl);
        } catch (Exception e) {
            return newCoverUrl;
        }finally {
            if(System.currentTimeMillis()/1000 -start > challengeAppConfig.getTimeLimit()) {
                log.info("s3上传图片用时：{}秒",
                        System.currentTimeMillis()/1000 -start);
            }
        }

        return newCoverUrl;
    }
}
